// 高阶函数的其他应用
// currying (函数柯里化)：部分求值。一个currying函数首先会接受一些参数，接受这些参数后，该函数并不会立即执行，而是继续返回另外一个函数，刚传入的参数会在比保重被保存起来。
/*
    // 计算每个月开销的函数
    var cost = (function() {
        var args = [];
        return function() {
            if (arguments.length === 0) {
                var money = 0;
                for (var i = 0; i < args.length; i++) {
                    money += args[i];
                }
                console.log(money);
                return money;
            } else {
                [].push.apply(args, arguments);
                console.log(args);
            }
        }
    })();

    cost(100)
    cost(100)
    cost(100)
    cost(100)
    cost()
 */

/*
    var currying = function(fn) {
        var args = [];
        return function() {
            if (arguments.length === 0) {
                return fn.apply(this, args);
            } else {
                [].push.apply(args, arguments);
                return arguments.callee;
            }
        }
    };

    var cost = (function() {
        var money = 0;
        return function() {
            for (var i = 0; i < arguments.length; i++) {
                money += arguments[i];
            }
            return money;
        }
    })();
    var total = currying(cost);
    total(100);
    total(200);
    total(300);
    total(400);
    total(500);
    console.log(total());
 */


// uncurrying(泛化)
/*
    // 在Javascript中，当我们调用对象的某个方法时，其实不用去关心该对象是否被设计为拥有这个方法，一个对象也不限于只能使用自己的方法---使用call或者apply动态调用，可以使用其他对象的方法。这样该方法中的this就不在局限于原对象，而是被泛化，从而得到更广泛的应用。
    // 泛化函数
    Function.prototype.uncurrying = function() {
        var self = this; // self 保存的是context 调用的函数
        return function() {
            var obj = Array.prototype.shift.call(arguments);
            return self.apply(obj, arguments);
        }
    }

    var push = Array.prototype.push.uncurrying();
    (function() {
        push(arguments, 4);
        console.log(arguments)
    })(1,2,3)
 */
/*
 var uncurryArray = (function() {
    Function.prototype.uncurrying = function() {
        var self = this;
        return function() {
            var obj = Array.prototype.shift.call(arguments);
            return self.apply(obj, arguments);
        }
    };

    for (var i = 0, fn, ary = ['push', 'shift', 'forEach']; fn = ary[i++];) {
        Array[fn] = Array.prototype[fn].uncurrying();
    }
 })();

var obj = {
    name: 'fywang15'
};
Array.push(obj, 3);
Array.push(obj, 4);
Array.push(obj, 3);
console.log(obj)

Array.shift(obj, 4);
console.log(obj)
 */


(function(ary) {
    Function.prototype.uncurrying = function() {
        var self = this;
        return function() {
            var obj = Array.prototype.shift.apply(arguments);
            return self.apply(obj, arguments);
        }
    }

    for (var i = 0, fn; fn = ary[i++];) {
        Array[fn] = Array.prototype[fn].uncurrying();
    }
})(['push', 'pop', 'unshift', 'shift', 'forEach', 'some']);
var obj = {
    name: 'fywang15'
};
Array.push(obj, 3);
Array.push(obj, 4);
Array.push(obj, 3);
console.log(obj)

Array.shift(obj, 4);
console.log(obj)
